<HTML>
<HEAD>
<TITLE>Transform Record and related software</TITLE>
</HEAD>
<BODY>
<H1>Transform Record and related software</H1>

<ADDRESS>Tim Mooney</ADDRESS>

<HR>
<H2>Contents</H2>
<UL>
<LI><A HREF="#Overview">Overview</A>
<LI><A HREF="#Fields">Field Descriptions</A>
<LI><A HREF="#Expressions">Expressions</A>
<LI><A HREF="#Files">Files</A>
<LI><A HREF="#Restrictions">Restrictions</A>
<LI><A HREF="#Release notes">Release notes</A>
</UL>

<A NAME="Overview">
<H2>Overview</H2></A>

This documentation describes version 5.8, and earlier, of the EPICS transform
record, and related EPICS software recommended for building and using it.
Version 5.8 is compatible with EPICS Release 3.14.x, and it may be
compatible with later releases, but it is not compatible with any earlier
releases of EPICS.


<P>The TRANSFORM record combines features of the CALC and SEQUENCE records,
with 16 sets of the following fields:<BR>
<DL compact>
<DT>input link <DD>INPA...INPP</DD>
<DT>input-link status <DD>IAV...IPV</DD>
<DT>input/output value <DD>A...P
<DT>expression <DD>CLCA...CLCP
<DT>output link <DD>OUTA...OUTP
<DT>output-link status <DD>OAV...OAP
<DT>comment <DD>CMTA...CMTP
</DL>

<P>There are guaranteed rules governing the sequence and conditions under
which expressions are evaluated.  Each time the record is processed, the
following sequence occurs:
<OL>
<LI>Values are fetched, in order A through P, from
all valid input links.  That is, if INPA is a valid input
link, the value of the field pointed to by INPA will be placed
into the field A, and so on.

<blockquote>Note: If the record is in link alarm (.NSEV >= INVALID_ALARM)
after all input-link values have been fetched, and if .IVLA == "Do Nothing",
then the record will quit processing at this point.  It will do some clean up,
but it will not execute its forward link.</blockquote>

<LI>Valid expressions are evaluated in order CLCA through CLCP, and the
resulting values are placed into the corresponding fields, A through P.
Expressions are not always evaluated, however:

<P>If COPT=="Conditional" (0; the default value), then expression CLC<i>x</i> is
evaluated only if <i>x</i> is "old", as defined below.  In other words, new
values are regarded as independent variables in the set of equations
CLCA...CLCP, and unchanged/unwritten values are regarded as dependent variables.

<P>If COPT=="Always" (1), all valid expressions are evaluated unconditionally.


<blockquote> The value field <i>x</i> is "old" if it has the same value it had after the
last time the record was processed, and it was not written to (either by an
outside agent or by the input link, INP<i>x</i>) since the last time the record was
processed.  

<P>Note that this means you cannot use both INPA and CLCA, unless you set
COPT=="Always".

<P>Note that writes received while PACT==1 are special: they will change the
field they write to, but they will not be regarded as writes for the purpose of
determining whether a value is "new".  This rule allows a transform record to
write to itself (using database links) without messing up its notion of which
values are new. 

<P>Prior to version 5.8, there was no COPT field, and the record always behaved
as though COPT=="Conditional".

</blockquote>

<LI>Valid output links are triggered in order OUTA through OUTP---regardless
of whether the corresponding values have changed.  That is, if OUTA is a
valid link, the value in field A is poked into the field pointed to by
OUTA, and so on.
</OL>

<P>The transform record uses the expression-evaluation software
sCalcPostfix.c and sCalcPerform.c, originally developed for the
sCalcout record.  An expression may contain any of the functions
and constants that are valid for the sCalcout record (including string
functions, though a final string result will of course be converted to
double); any of the letters A-P, which stand for the values of the
corresponding fields in the instant before the expression is evaluated;
the expression @n, where n is an integer in [0-15], or an expression
that yields such an integer, stands for a value A-P; and any of the
constants PI (3.14159265), R2D (180/PI), D2R (PI/180), S2R (D2R/3600),
and R2S (R2D*3600).

<A NAME="Background">
<H2>Background</H2></A>
The TRANSFORM record was originally intended to perform the sequences of
conditional calculations required to implement bidirectional coordinate
transformations.

<P>Example:  You have defined two records containing values we'll call "L" and
"R" (the left and right edges of a slit, say).  Sometimes the user wants to
control L and R individually, and sometimes he wants to control a
combination of L and R--say (L-R) and (L+R)/2, the width and center of the
slit system.  You can implement a bidirectional coordinate transformation
with the following expressions (where position values are assumed to
increase as we go from left to right):

<TABLE BORDER>
<TR VALIGN=TOP><TH>field <TH>expression <TH>comment
<TR VALIGN=TOP><TD>A <TD>C-D/2 <TD>position of left edge of slit
<TR VALIGN=TOP><TD>B <TD>C+D/2 <TD>position of right edge of slit
<TR VALIGN=TOP><TD>C <TD>(A+B)/2 <TD>position of center of slit
<TR VALIGN=TOP><TD>D <TD>B-A <TD>width of slit
</TABLE>

<P>Now, if a user command moves the left side of the slit (A changes) and
causes the record to process, A will not be recalculated because it's value
is new, the right side of the slit will remain
still (B is unnecessarily recalculated from old values of C and D), the
position of the slit center (C) will change as expected, and the slit width
(D) will change as expected.  Thus, all four fields will contain consistent
information about the two degrees of freedom controlled by the record, and
effectively we have two actual devices and two virtual devices.

<P>We don't care which two fields (out of A..D) correspond to actual
motion-control devices, and two channel-access clients that make different
assumptions about how a slit should be implemented can control this
slit without modification.  With an additional, similar transform
record driven from the readback fields of the actual motion-control
devices, we can calculate readback values for the virtual devices as well.

<P>We could have accomplished nearly the same effect with six CALC records and
some FANOUTs, but two of the drive fields (A,B,C,D) would always be
inconsistent with their readbacks.
<P>

<A NAME="Expressions"> <H2>Expressions</H2></A> Expressions for the transform
record are described in  <a href="sCalcoutRecord.html">sCalcoutRecord.html</a>,
because the transform record uses the same expression evaluation software.

<H3>Synonyms</H3>
<P>In addition to conventional expression, like "A+B", you can specify
<i>synonyms</i> for the variables "A" through "P", as demonstrated below:

<P><center><IMG SRC="oldTransform.adl.jpg"><br>conventional expressions</IMG></center>
<P><center><IMG SRC="newTransform.adl.jpg"><br>expressions with user specified synonyms</IMG></center>

<P>To specify a synonym for the variable "A", you begin the comment field "CMTA"
with the synonym, which must begin with '$', and which is terminated
by the first nonalphanumeric character.  For example, in the comment "$left:the left slit",
the synonym is "$left".

<A NAME="Fields">
<H2>Field Descriptions</H2></A>
In addition to fields common to all record types (see the EPICS Record
Reference Manual for these) the transform record has the fields described below.

<HR><!--------------------------------------------------------------------------------------------------------->
<TABLE BORDER CELLPADDING=1>
<A NAME="Fields_alphabetical">
<CAPTION><H2>Alphabetical list of record-specific fields</H2>
</CAPTION></A>

<TR><TH>Name								<TH>Access	<TH>Prompt				<TH>Data type	<TH>Comment
 
<TR><TD>A    <TD>R/W(*)	<TD>Value A				<TD>DOUBLE		<TD>
<TR><TD>B    <TD>R/W(*)	<TD>Value B				<TD>DOUBLE		<TD>
<TR><TD>C    <TD>R/W(*)	<TD>Value C				<TD>DOUBLE		<TD>
<TR><TD>CAV	 <TD>R		<TD>Expression Invalid	<TD>LONG		<TD>Expression CLCA invalid if nonzero
<TR><TD>CBV	 <TD>R		<TD>Expression Invalid	<TD>LONG		<TD>Expression CLCB invalid if nonzero
<TR><TD>CCV	 <TD>R		<TD>Expression Invalid	<TD>LONG		<TD>Expression CLCC invalid if nonzero
<TR><TD>CDV	 <TD>R		<TD>Expression Invalid	<TD>LONG		<TD>Expression CLCD invalid if nonzero
<TR><TD>CEV	 <TD>R		<TD>Expression Invalid	<TD>LONG		<TD>Expression CLCE invalid if nonzero
<TR><TD>CFV	 <TD>R		<TD>Expression Invalid	<TD>LONG		<TD>Expression CLCF invalid if nonzero
<TR><TD>CGV	 <TD>R		<TD>Expression Invalid	<TD>LONG		<TD>Expression CLCG invalid if nonzero
<TR><TD>CHV	 <TD>R		<TD>Expression Invalid	<TD>LONG		<TD>Expression CLCH invalid if nonzero
<TR><TD>CIV	 <TD>R		<TD>Expression Invalid	<TD>LONG		<TD>Expression CLCI invalid if nonzero
<TR><TD>CJV	 <TD>R		<TD>Expression Invalid	<TD>LONG		<TD>Expression CLCJ invalid if nonzero
<TR><TD>CKV	 <TD>R		<TD>Expression Invalid	<TD>LONG		<TD>Expression CLCK invalid if nonzero
<TR><TD>CLCA <TD>R/W*	<TD>Expression A		<TD>STRING(120)	<TD>
<TR><TD>CLCB <TD>R/W*	<TD>Expression B		<TD>STRING(120)	<TD>
<TR><TD>CLCC <TD>R/W*	<TD>Expression C		<TD>STRING(120)	<TD>
<TR><TD>CLCD <TD>R/W*	<TD>Expression D		<TD>STRING(120)	<TD>
<TR><TD>CLCE <TD>R/W*	<TD>Expression E		<TD>STRING(120)	<TD>
<TR><TD>CLCF <TD>R/W*	<TD>Expression F		<TD>STRING(120)	<TD>
<TR><TD>CLCG <TD>R/W*	<TD>Expression G		<TD>STRING(120)	<TD>
<TR><TD>CLCH <TD>R/W*	<TD>Expression H		<TD>STRING(120)	<TD>
<TR><TD>CLCI <TD>R/W*	<TD>Expression I		<TD>STRING(120)	<TD>
<TR><TD>CLCJ <TD>R/W*	<TD>Expression J		<TD>STRING(120)	<TD>
<TR><TD>CLCK <TD>R/W*	<TD>Expression K		<TD>STRING(120)	<TD>
<TR><TD>CLCL <TD>R/W*	<TD>Expression L		<TD>STRING(120)	<TD>
<TR><TD>CLCM <TD>R/W*	<TD>Expression M		<TD>STRING(120)	<TD>
<TR><TD>CLCN <TD>R/W*	<TD>Expression N		<TD>STRING(120)	<TD>
<TR><TD>CLCO <TD>R/W*	<TD>Expression O		<TD>STRING(120)	<TD>
<TR><TD>CLCP <TD>R/W*	<TD>Expression P		<TD>STRING(120)	<TD>
<TR><TD>CLV	 <TD>R		<TD>Expression Invalid	<TD>LONG		<TD>Expression CLCL invalid if nonzero
<TR><TD>CMTA <TD>R/W		<TD>Comment				<TD>STRING(39)	<TD>
<TR><TD>CMTB <TD>R/W		<TD>Comment				<TD>STRING(39)	<TD>
<TR><TD>CMTC <TD>R/W		<TD>Comment				<TD>STRING(39)	<TD>
<TR><TD>CMTD <TD>R/W		<TD>Comment				<TD>STRING(39)	<TD>
<TR><TD>CMTE <TD>R/W		<TD>Comment				<TD>STRING(39)	<TD>
<TR><TD>CMTF <TD>R/W		<TD>Comment				<TD>STRING(39)	<TD>
<TR><TD>CMTG <TD>R/W		<TD>Comment				<TD>STRING(39)	<TD>
<TR><TD>CMTH <TD>R/W		<TD>Comment				<TD>STRING(39)	<TD>
<TR><TD>CMTI <TD>R/W		<TD>Comment				<TD>STRING(39)	<TD>
<TR><TD>CMTJ <TD>R/W		<TD>Comment				<TD>STRING(39)	<TD>
<TR><TD>CMTK <TD>R/W		<TD>Comment				<TD>STRING(39)	<TD>
<TR><TD>CMTL <TD>R/W		<TD>Comment				<TD>STRING(39)	<TD>
<TR><TD>CMTM <TD>R/W		<TD>Comment				<TD>STRING(39)	<TD>
<TR><TD>CMTN <TD>R/W		<TD>Comment				<TD>STRING(39)	<TD>
<TR><TD>CMTO <TD>R/W		<TD>Comment				<TD>STRING(39)	<TD>
<TR><TD>CMTP <TD>R/W		<TD>Comment				<TD>STRING(39)	<TD>
<TR><TD>CMV	 <TD>R		<TD>Expression Invalid	<TD>LONG		<TD>Expression CLCM invalid if nonzero
<TR><TD>CNV	 <TD>R		<TD>Expression Invalid	<TD>LONG		<TD>Expression CLCN invalid if nonzero
<TR><TD>COPT <TD>R/W	<TD>Calc option			<TD>MENU: <DL
compact><DT>0<DD>Conditional<DT>1<DD>Always</DL><TD>Calcs performed conditionally, or always?
<TR><TD>COV	 <TD>R		<TD>Expression Invalid	<TD>LONG		<TD>Expression CLCO invalid if nonzero
<TR><TD>CPV	 <TD>R		<TD>Expression Invalid	<TD>LONG		<TD>Expression CLCP invalid if nonzero
<TR><TD>D    <TD>R/W(*)	<TD>Value D				<TD>DOUBLE		<TD>
<TR><TD>E    <TD>R/W(*)	<TD>Value E				<TD>DOUBLE		<TD>
<TR><TD>EGU  <TD>R/W		<TD>Units name			<TD>STRING(16)	<TD>
<TR><TD>F    <TD>R/W(*)	<TD>Value F				<TD>DOUBLE		<TD>
<TR><TD>G    <TD>R/W(*)	<TD>Value G				<TD>DOUBLE		<TD>
<TR><TD>H    <TD>R/W(*)	<TD>Value H				<TD>DOUBLE		<TD>
<TR><TD>I    <TD>R/W(*)	<TD>Value I				<TD>DOUBLE		<TD>
<TR><TD>IAV	 <TD>R		<TD>Link Valid			<TD>MENU:<DL compact>

<DT>0<DD>Ext PV NC
<DT>1<DD>Ext PV OK
<DT>2<DD>Local PV
<DT>3<DD>Constant
</DL>

		<TD>Link INPA Valid if nonzero
<TR><TD>IBV	 <TD>R		<TD>Link Valid			<TD>MENU (see IAV)		<TD>Link INPB Valid if nonzero
<TR><TD>ICV	 <TD>R		<TD>Link Valid			<TD>MENU (see IAV)		<TD>Link INPC Valid if nonzero
<TR><TD>IDV	 <TD>R		<TD>Link Valid			<TD>MENU (see IAV)		<TD>Link INPD Valid if nonzero
<TR><TD>IEV	 <TD>R		<TD>Link Valid			<TD>MENU (see IAV)		<TD>Link INPE Valid if nonzero
<TR><TD>IFV	 <TD>R		<TD>Link Valid			<TD>MENU (see IAV)		<TD>Link INPF Valid if nonzero
<TR><TD>IGV	 <TD>R		<TD>Link Valid			<TD>MENU (see IAV)		<TD>Link INPG Valid if nonzero
<TR><TD>IHV	 <TD>R		<TD>Link Valid			<TD>MENU (see IAV)		<TD>Link INPH Valid if nonzero
<TR><TD>IIV	 <TD>R		<TD>Link Valid			<TD>MENU (see IAV)		<TD>Link INPI Valid if nonzero
<TR><TD>IJV	 <TD>R		<TD>Link Valid			<TD>MENU (see IAV)		<TD>Link INPJ Valid if nonzero
<TR><TD>IKV	 <TD>R		<TD>Link Valid			<TD>MENU (see IAV)		<TD>Link INPK Valid if nonzero
<TR><TD>ILV	 <TD>R		<TD>Link Valid			<TD>MENU (see IAV)		<TD>Link INPL Valid if nonzero
<TR><TD>IMV	 <TD>R		<TD>Link Valid			<TD>MENU (see IAV)		<TD>Link INPM Valid if nonzero
<TR><TD>INPA <TD>R/W		<TD>Input Link			<TD>LINK		<TD>
<TR><TD>INPB <TD>R/W		<TD>Input Link			<TD>LINK		<TD>
<TR><TD>INPC <TD>R/W		<TD>Input Link			<TD>LINK		<TD>
<TR><TD>INPD <TD>R/W		<TD>Input Link			<TD>LINK		<TD>
<TR><TD>INPE <TD>R/W		<TD>Input Link			<TD>LINK		<TD>
<TR><TD>INPF <TD>R/W		<TD>Input Link			<TD>LINK		<TD>
<TR><TD>INPG <TD>R/W		<TD>Input Link			<TD>LINK		<TD>
<TR><TD>INPH <TD>R/W		<TD>Input Link			<TD>LINK		<TD>
<TR><TD>INPI <TD>R/W		<TD>Input Link			<TD>LINK		<TD>
<TR><TD>INPJ <TD>R/W		<TD>Input Link			<TD>LINK		<TD>
<TR><TD>INPK <TD>R/W		<TD>Input Link			<TD>LINK		<TD>
<TR><TD>INPL <TD>R/W		<TD>Input Link			<TD>LINK		<TD>
<TR><TD>INPM <TD>R/W		<TD>Input Link			<TD>LINK		<TD>
<TR><TD>INPN <TD>R/W		<TD>Input Link			<TD>LINK		<TD>
<TR><TD>INPO <TD>R/W		<TD>Input Link			<TD>LINK		<TD>
<TR><TD>INPP <TD>R/W		<TD>Input Link			<TD>LINK		<TD>
<TR><TD>INV  <TD>R		<TD>Link Valid			<TD>MENU (see IAV)		<TD>Link INPN Valid if nonzero
<TR><TD>IOV  <TD>R		<TD>Link Valid			<TD>MENU (see IAV)		<TD>Link INPO Valid if nonzero
<TR><TD>IPV  <TD>R		<TD>Link Valid			<TD>MENU (see IAV) 		<TD>Link INPP Valid if nonzero
<TR><TD>IVLA  <TD>R             <TD>Invalid Link Action <TD>MENU: <DL
compact><DT>0<DD>Ignore error<DT>1<DD>Do Nothing</DL>
<TD>Selects what to do if the record is in link alarm.  "Do Nothing"
means quit wrap up and quit executing after input values have been
fetched.  The forward link will not be processed in this case.
<TR><TD>J    <TD>R/W(*)	<TD>Value J				<TD>DOUBLE		<TD>
<TR><TD>K    <TD>R/W(*)	<TD>Value K				<TD>DOUBLE		<TD>
<TR><TD>L    <TD>R/W(*)	<TD>Value L				<TD>DOUBLE		<TD>
<TR><TD>LA   <TD>R		<TD>Prev Value of A		<TD>DOUBLE		<TD>
<TR><TD>LB   <TD>R		<TD>Prev Value of B		<TD>DOUBLE		<TD>
<TR><TD>LC   <TD>R		<TD>Prev Value of C		<TD>DOUBLE		<TD>
<TR><TD>LD   <TD>R		<TD>Prev Value of D		<TD>DOUBLE		<TD>
<TR><TD>LE   <TD>R		<TD>Prev Value of E		<TD>DOUBLE		<TD>
<TR><TD>LF   <TD>R		<TD>Prev Value of F		<TD>DOUBLE		<TD>
<TR><TD>LG   <TD>R		<TD>Prev Value of G		<TD>DOUBLE		<TD>
<TR><TD>LH   <TD>R		<TD>Prev Value of H		<TD>DOUBLE		<TD>
<TR><TD>LI   <TD>R		<TD>Prev Value of I		<TD>DOUBLE		<TD>
<TR><TD>LJ   <TD>R		<TD>Prev Value of J		<TD>DOUBLE		<TD>
<TR><TD>LK   <TD>R		<TD>Prev Value of K		<TD>DOUBLE		<TD>
<TR><TD>LL   <TD>R		<TD>Prev Value of L		<TD>DOUBLE		<TD>
<TR><TD>LM   <TD>R		<TD>Prev Value of M		<TD>DOUBLE		<TD>
<TR><TD>LN   <TD>R		<TD>Prev Value of N		<TD>DOUBLE		<TD>
<TR><TD>LO   <TD>R		<TD>Prev Value of O		<TD>DOUBLE		<TD>
<TR><TD>LP   <TD>R		<TD>Prev Value of P		<TD>DOUBLE		<TD>
<TR><TD>M    <TD>R/W(*)	<TD>Value M				<TD>DOUBLE		<TD>
<TR><TD>MAP  <TD>R		<TD>Input bitmap		<TD>SHORT		<TD>
<TR><TD>N    <TD>R/W(*)	<TD>Value N				<TD>DOUBLE		<TD>
<TR><TD>O    <TD>R/W(*)	<TD>Value O				<TD>DOUBLE		<TD>
<TR><TD>OAV   <TD>R		<TD>Link Valid			<TD>MENU (see IAV)		<TD>Link Valid if nonzero
<TR><TD>OBV   <TD>R		<TD>Link Valid			<TD>MENU (see IAV)		<TD>Link Valid if nonzero
<TR><TD>OCV   <TD>R		<TD>Link Valid			<TD>MENU (see IAV)		<TD>Link Valid if nonzero
<TR><TD>ODV   <TD>R		<TD>Link Valid			<TD>MENU (see IAV)		<TD>Link Valid if nonzero
<TR><TD>OEV   <TD>R		<TD>Link Valid			<TD>MENU (see IAV)		<TD>Link Valid if nonzero
<TR><TD>OFV   <TD>R		<TD>Link Valid			<TD>MENU (see IAV)		<TD>Link Valid if nonzero
<TR><TD>OGV   <TD>R		<TD>Link Valid			<TD>MENU (see IAV)		<TD>Link Valid if nonzero
<TR><TD>OHV   <TD>R		<TD>Link Valid			<TD>MENU (see IAV)		<TD>Link Valid if nonzero
<TR><TD>OIV   <TD>R		<TD>Link Valid			<TD>MENU (see IAV)		<TD>Link Valid if nonzero
<TR><TD>OJV   <TD>R		<TD>Link Valid			<TD>MENU (see IAV)		<TD>Link Valid if nonzero
<TR><TD>OKV   <TD>R		<TD>Link Valid			<TD>MENU (see IAV)		<TD>Link Valid if nonzero
<TR><TD>OLV   <TD>R		<TD>Link Valid			<TD>MENU (see IAV)		<TD>Link Valid if nonzero
<TR><TD>OMV   <TD>R		<TD>Link Valid			<TD>MENU (see IAV)		<TD>Link Valid if nonzero
<TR><TD>ONV   <TD>R		<TD>Link Valid			<TD>MENU (see IAV)		<TD>Link Valid if nonzero
<TR><TD>OOV   <TD>R		<TD>Link Valid			<TD>MENU (see IAV)		<TD>Link Valid if nonzero
<TR><TD>OPV   <TD>R		<TD>Link Valid			<TD>MENU (see IAV)		<TD>Link Valid if nonzero
<TR><TD>OUTA  <TD>R/W		<TD>Output Link			<TD>LINK		<TD>
<TR><TD>OUTB  <TD>R/W		<TD>Output Link			<TD>LINK		<TD>
<TR><TD>OUTC  <TD>R/W		<TD>Output Link			<TD>LINK		<TD>
<TR><TD>OUTD  <TD>R/W		<TD>Output Link			<TD>LINK		<TD>
<TR><TD>OUTE  <TD>R/W		<TD>Output Link			<TD>LINK		<TD>
<TR><TD>OUTF  <TD>R/W		<TD>Output Link			<TD>LINK		<TD>
<TR><TD>OUTG  <TD>R/W		<TD>Output Link			<TD>LINK		<TD>
<TR><TD>OUTH  <TD>R/W		<TD>Output Link			<TD>LINK		<TD>
<TR><TD>OUTI  <TD>R/W		<TD>Output Link			<TD>LINK		<TD>
<TR><TD>OUTJ  <TD>R/W		<TD>Output Link			<TD>LINK		<TD>
<TR><TD>OUTK  <TD>R/W		<TD>Output Link			<TD>LINK		<TD>
<TR><TD>OUTL  <TD>R/W		<TD>Output Link			<TD>LINK		<TD>
<TR><TD>OUTM  <TD>R/W		<TD>Output Link			<TD>LINK		<TD>
<TR><TD>OUTN  <TD>R/W		<TD>Output Link			<TD>LINK		<TD>
<TR><TD>OUTO  <TD>R/W		<TD>Output Link			<TD>LINK		<TD>
<TR><TD>OUTP  <TD>R/W		<TD>Output Link			<TD>LINK		<TD>
<TR><TD>P     <TD>R/W(*)	<TD>Value P				<TD>DOUBLE		<TD>
<TR><TD>PREC  <TD>R/W		<TD>Display Precision	<TD>MENU		<TD>
<TR><TD>RPCA  <TD>R		<TD>Postfix Expression	<TD>CHAR *		<TD>
<TR><TD>RPCB  <TD>R		<TD>Postfix Expression	<TD>CHAR *		<TD>
<TR><TD>RPCC  <TD>R		<TD>Postfix Expression	<TD>CHAR *		<TD>
<TR><TD>RPCD  <TD>R		<TD>Postfix Expression	<TD>CHAR *		<TD>
<TR><TD>RPCE  <TD>R		<TD>Postfix Expression	<TD>CHAR *		<TD>
<TR><TD>RPCF  <TD>R		<TD>Postfix Expression	<TD>CHAR *		<TD>
<TR><TD>RPCG  <TD>R		<TD>Postfix Expression	<TD>CHAR *		<TD>
<TR><TD>RPCH  <TD>R		<TD>Postfix Expression	<TD>CHAR *		<TD>
<TR><TD>RPCI  <TD>R		<TD>Postfix Expression	<TD>CHAR *		<TD>
<TR><TD>RPCJ  <TD>R		<TD>Postfix Expression	<TD>CHAR *		<TD>
<TR><TD>RPCK  <TD>R		<TD>Postfix Expression	<TD>CHAR *		<TD>
<TR><TD>RPCL  <TD>R		<TD>Postfix Expression	<TD>CHAR *		<TD>
<TR><TD>RPCM  <TD>R		<TD>Postfix Expression	<TD>CHAR *		<TD>
<TR><TD>RPCN  <TD>R		<TD>Postfix Expression	<TD>CHAR *		<TD>
<TR><TD>RPCO  <TD>R		<TD>Postfix Expression	<TD>CHAR *		<TD>
<TR><TD>RPCP  <TD>R		<TD>Postfix Expression	<TD>CHAR *		<TD>
<TR><TD>RPVT  <TD>R		<TD>Record private info	<TD>VOID *		<TD>
<TR><TD>VAL   <TD>R/W		<TD>VAL field			<TD>DOUBLE		<TD>not used
<TR><TD>VERS  <TD>R		<TD>Code Version		<TD>FLOAT		<TD>

<TR VALIGN=TOP>
<TD COLSPAN=5, ALIGN=LEFT>
<TABLE>
<TD COLSPAN=3> Note: In the <B>Access</B> column above: </TD>
<TR VALIGN=TOP>
<TD>R</TD>    <TD>Read only<TD>
</TR>
<TR VALIGN=TOP>
<TD>r</TD>    <TD>Read only, not posted<TD>
</TR>
<TR VALIGN=TOP>
<TD>R/W</TD>  <TD>Read and write are allowed</TD>
</TR>
<TR VALIGN=TOP>
<TD>R/W*</TD> <TD>Read and write are allowed; channel-access write triggers record 
processing if the record's SCAN field is set to "Passive."</TD>
</TR>
<TR VALIGN=TOP>
<TD>R/W(*)</TD> <TD>Read and write are allowed; channel-access write triggers record 
processing if the corresponding trigger field (.xPP) is nonzero and record's SCAN field is set to "Passive."</TD>
</TR>
<TD COLSPAN=3> Note: Link Valid fields IxV and OxV actually take the following values:
<UL>
<LI>0: "Ext PV NC" Link is to an external PV.  Channel-access connection does not exist (yet?)
<LI>1: "Ext PV OK" Link is to an external PV.  Channel-access onnection exists.
<LI>2: "Local PV" Link is to a local PV.
<LI>3: "Constant" No PV name has been given for this link.
</UL>
</TABLE>

</TABLE>
</HR>


<HR><!--------------------------------------------------------------------------------------------------------->
<P>
<A NAME="Files"><H2>Files</H2></A> The following table briefly
describes the files required to implement and use the transform
record.  The reader is assumed to be familiar with building EPICS.

<!--------------------------------------------------------------------->
<P><TABLE BORDER CELLPADDING=1>
<TR><TH COLSPAN=2>
SOURCE CODE<BR>
files to be placed in <CODE>&lt;top&gt;/&lt;app&gt;App/src/</CODE>
</TH> </TR>
<TR VALIGN=TOP><TD>transformRecord.c	<TD>Record support code
<TR VALIGN=TOP><TD>transformRecord.dbd	<TD>Database definition file
<TR VALIGN=TOP><TD>sCalcPerform.c  	<TD>string calculation support
<TR VALIGN=TOP><TD>sCalcPostfix.c  	<TD>string calculation support
<TR VALIGN=TOP><TD>sCalcPostfix.h  	<TD>string calculation support
<TR VALIGN=TOP><TD>sCalcPostfixPvt.h  	<TD>string calculation support
</TR>
</TABLE>

<!--------------------------------------------------------------------->
<P><TABLE BORDER CELLPADDING=1>
<TR><TH COLSPAN=2>DATABASES<BR>
files to be placed in 
<CODE>&lt;top&gt;/&lt;app&gt;App/Db/</CODE>
</TH> </TR>

<TR VALIGN=TOP><TD>userTransform.db		<TD>Sample transform-record database
<TR VALIGN=TOP><TD>userTransforms10.db	<TD>10 transforms and an enable switch
<TR VALIGN=TOP><TD>userTransforms10_settings.req	<TD>save-restore request file for userTransforms10.db</TABLE>
</TABLE>
<!--------------------------------------------------------------------->
<P><TABLE BORDER CELLPADDING=1>
<TR><TH COLSPAN=2>MEDM DISPLAY FILES<BR>
files to be placed in 
<CODE>&lt;top&gt;/&lt;app&gt;App/op/adl/</CODE>
</TH> </TR>

<TR VALIGN=TOP><TD>yyTransform.adl		<TD>Small control display for any transform record
<TR VALIGN=TOP><TD>yyTransform_full.adl	<TD>...with more detail

<TR VALIGN=TOP><TD>userTransform.adl	<TD>Small control display for transform record enabled by the switch in userTransforms10.db
<TR VALIGN=TOP><TD>userTransform_full.adl	<TD>...with more detail
<TR VALIGN=TOP><TD>userTransforms10.adl	<TD>Collection of userTransform callups, with overall enable switch
<TR><TD COLSPAN=2>These files build <CODE>medm</CODE> screens to access the transform record.
To use one of them from the command line, type, for example
<PRE>
medm -x -macro "P=xxx:,T=userTran1" yyTransform_full.adl
</PRE>
<P>
where <CODE>xxx:userTran1</CODE> is the name of the transform record.
</TD>
</TR>
</TABLE>

<!--------------------------------------------------------------------->
<P><TABLE BORDER CELLPADDING=1>
<TR><TH COLSPAN=2>EPICS STARTUP FILES<BR>
files to be placed in 
<CODE>&lt;top&gt;/iocBoot/ioc&lt;name&gt;/</CODE>
</TH> </TR>

<TR VALIGN=TOP><TD>st.cmd		<TD>Startup script
<TR><TD COLSPAN=2>
This file is not included in the distribution.  The following line added to st.cmd loads a single transform record.

<PRE>
dbLoadRecords("xxxApp/Db/userTransform.db","P=xxx:,N=1")
</PRE>
</TD>
</TR>
</TABLE>

<!--------------------------------------------------------------------->
<P><TABLE BORDER CELLPADDING=1>
<TR><TH COLSPAN=2>BACKUP/RESTORE (BURT) REQUEST FILE<BR>
files to be placed in <CODE>&lt;top&gt;/&lt;app&gt;App/op/burt/</CODE>
</TH></TR>

<TR VALIGN=TOP><TD>yyTransformSettings.req	<TD>save settings of a specified transform record.
This file is normally <CODE>#include</CODE>'d (once for each transform record) by other request files.
</TR>
</TABLE>


<!--------------------------------------------------------------------->
<P><TABLE BORDER CELLPADDING=1>
<TR><TH COLSPAN=2>AUTOSAVE/RESTORE REQUEST FILE<BR>
file to be placed in your autosave search path
</TH></TR>

<TR VALIGN=TOP><TD>transform_settings.req	<TD>save settings of a specified transform record.
This file is normally included once for each transform record by other request files, with a line of the following form:<br>
file transform_settings.req P=tmm:,T=userTran1
.
</TR>

<TR VALIGN=TOP><TD>userTransforms10_settings.req	<TD>save settings of the userTransforms10.db database.
.
</TR>
</TABLE>

<HR>
<A NAME="Restrictions"><H2>Restrictions</H2></A>
None that I'm aware of.

<HR>
Versions earlier than 5.8 did not have the COPT field.
<P>
<A NAME="Release notes"><H2>Release notes</H2></A>
Versions earlier than 5.7 did not post fields with
the DBE_LOG attribute.
<P>
Versions earlier than 5.6 expected sCalcPostfix
to allocate the postfix-expression array.  sCalcPostfix no longer does this,
and the transform record changed as a consequence.
<P>
Versions earlier than 5.5 ignored link errors.
Beginning with version 5.5, you can choose to ignore link errors (the default)
or to quit processing (after all input link values have been fetched and
transferred to their respective value fields).
<P>
In versions earlier than 5.2, the test for old values did not correctly handle
NaN values, which would always appear to be new, and would therefore never go
away.
<P>
Versions earlier than 5.0 defined the
additional fields APP...PPP, which determined whether or not a
channel-access put to the value fields A...P, respectively,
would cause the record to process.  (The default value of these fields
did not cause the record to process.)  The mechanism used to accomplish
this (scanOnce(), called from the transform record's special() routine)
was incompatible with EPICS execution tracing software, dbPutNotify(),
which must be able to discover from the .dbd file which fields of a record
cause processing when written to via channel access.  Because putNotify()
has become an essential feature of EPICS in synchrotron-radiation
applications (i.e., in synApps), the transform record was modified to
remove the &lt;x&gt;PP fields, and the fields A..P were
made process passive in transformRecord.dbd.


<HR>
<ADDRESS>
Suggestions and comments to: 
<BR><A HREF="mailto:mooney@aps.anl.gov">Tim Mooney</A> : (mooney@aps.anl.gov)
<BR>
</ADDRESS>

</BODY>
</HTML>
